#include "thread_pool.h"
#define CHUNK_SIZE 4096 // 定义每次读取文件内容的块大小
#define MMAP_THRESHOLD (1024 * 1024 * 100) // 文件大小阈值，单位为字节

void printProgressBar(double percentage) {
    const int width = 50;
    int progress = width * percentage;

    printf("\033[2K"); // 清除当前行
    printf("\033[0G"); // 将光标移动到行首
    printf("Progress: [");

    for (int i = 0; i < width; ++i) {
        if (i < progress) {
            printf("\u2588"); // Unicode 实心方块
        } else {
            printf("\u2591"); // Unicode 灰色方块
        }
    }

    printf("] %.2f%%", percentage * 100);
    fflush(stdout);
}                        

int mmap_transfer(off_t length, int fd, int sockfd)
{
    off_t total_sent = 0;
    off_t mmap_size = MMAP_THRESHOLD; //限制内存映射的大小
    while(total_sent < length) {
        if(total_sent + mmap_size > length) {
            mmap_size = length - total_sent; // 最后一次内存映射的大小可能会小于 MMAP_THRESHOLD
        }
        void* address = mmap(NULL, mmap_size, PROT_READ, MAP_SHARED, fd, total_sent);
        if(address == MAP_FAILED) {
            perror("mmap");
            return -1;
        }
        int ret = send(sockfd, address, mmap_size, 0);
        if(ret == -1) {
            perror("send");
            munmap(address, mmap_size);
            break;
        }
        if(munmap(address, mmap_size)) {
            perror("munmap");
        }
        total_sent += ret;

        // 打印进度条
        double percentage = (double)total_sent / length;
        printProgressBar(percentage);

        // usleep(1000);
    }
    printf("\nmmap File transfered successfully.\n");

    return 0;
}

int chunk_transfer(off_t length, int fd, int sockfd)
{
    // 逐块读取文件内容并发送
    char chunk[CHUNK_SIZE];
    ssize_t bytes_read, bytes_sent;
    off_t total_sent = 0;
    while ((bytes_read = read(fd, chunk, sizeof(chunk))) > 0) {
        bytes_sent = sendn(sockfd, chunk, bytes_read);
        if (bytes_sent == -1) {
            perror("send");
            break;
        }
        total_sent += bytes_sent;

        // 打印进度条
        double percentage = (double)total_sent / length;
        printProgressBar(percentage);

        usleep(1);
    }
    printf("\nFile transfered successfully.\n");

    return 0;
}

int transferFile(int sockfd, char* filename)
{
    // 1. 检查文件名是否为空
    if (strlen(filename) == 0) {
        printf("File name is empty.\n");
        return -1;
    }

    // 2. 打开文件并获取文件长度
    int fd = open(filename, O_RDONLY);
    if (fd == -1) {
        printf("File not found.\n");
        return -1;
    }

    // 3. 发送文件名
    // 3.1设置文件名的长度
    train_t2 t;
    memset(&t, 0, sizeof(t));
    t.len = strlen(filename);
    strcpy(t.buff, filename);
    sendn(sockfd, &t, 4 + t.len);

    // 3.2 获取文件的大小
    struct stat fileInfo;
    memset(&fileInfo, 0, sizeof(fileInfo));
    fstat(fd, &fileInfo);
    off_t length = fileInfo.st_size;
    printf("file content size: %ld\n", length);

    // 4. 发送文件大小
    sendn(sockfd, &length, sizeof(length));

    // 5.断点续传判断客户端文件是否存在
    // 5.1客户端已经存在相同文件名字，接收从客户端发过来的文件大小
    off_t client_file_size = 0;
    int ret = recvn(sockfd, &client_file_size, sizeof(client_file_size));
    if(ret < 0) {
        perror("recv client_file_size");
        return -1;
    }else {
        printf("client_file_size: %ld\n", client_file_size);
    }
    // 6.判断是哪种情况
    if(client_file_size == length) {
        // 6.1证明客户端已经存在相同大小的文件，不需要进行断点传输
        printf("client file already exist.\n");
        return 0;
    }else if(client_file_size >= 0 && client_file_size < length) {
        // 6.3向客户端发送客户端需要接收的文件的大小
        off_t current_size = length - client_file_size;
        printf("client need %ld bytes more.\n", current_size);
        ret = sendn(sockfd, &current_size, sizeof(current_size));
        if(ret < 0) {
            perror("sendn");
            return -1;
        }
        // 6.2客户端存在相同文件且并未发送完毕，进行断点传输
        // 偏移至文件需要发送剩余bytes的位置
        off_t offset = lseek(fd, client_file_size, SEEK_SET);
          if(offset == -1) {
          perror("lseek");
          close(fd);
          return -1;
          }
          printf("offset: %ld\n", offset);
        if(current_size > MMAP_THRESHOLD) {
            //使用mmap发送大文件
            mmap_transfer(current_size, fd, sockfd);
        }else {
            chunk_transfer(current_size, fd, sockfd);
        }
    }else if(client_file_size == -1){
        printf("client file do not exist and transfer: %ld.\n", client_file_size);
        // 6.4再向客户端发送文件大小长度
        sendn(sockfd, &length, sizeof(length));
        // 6.3客户端不存在相同的文件，直接进行传输
        if(length > MMAP_THRESHOLD) {
            //使用mmap发送大文件
            mmap_transfer(length, fd, sockfd);
        }else {
            chunk_transfer(length, fd, sockfd);
        }
    }

    // 6. 关闭文件描述符
    close(fd);
    return 0;
}

